package server;

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import server.tasks.MonitorListener;
import server.tasks.MonitorTask;


public class DbMonitor implements Runnable {
	private Collection<NodeInfo> nodes;	
	private Collection<MonitorListener> listeners;
	private ExecutorService exec;
	private boolean stopped = false;
	private long msTimeout = 15000;
	
	public DbMonitor(ExecutorService exec) {
		this.exec = exec;
		this.listeners = new ArrayList<MonitorListener>();
	}
	
	@Override
	public void run() {		
		Logger.logEvent("Monitorowanie wezlow rozpoczete", Logger.LOG_INFO);
		Collection<MonitorTask> startedTasks = new ArrayList<MonitorTask>();
		
		while(isStopped() == false) {		
			Logger.logEvent("Zbieranie danych diagnostycznych", Logger.LOG_INFO);
			Collection<MonitoringData> monitoringResult = new ArrayList<MonitoringData>();
			long monitorStart = System.currentTimeMillis();
			
			for(NodeInfo info : nodes) {
				MonitorTask task = new MonitorTask(info, monitorStart);
				Future<MonitorTask> future = exec.submit(task);
				task.future = future;
				startedTasks.add(task);
			}
			
			for(MonitorTask t : startedTasks) {
				try {
					//wymus zakonczenie watku w czasie timeoutu
					t.future.get(this.msTimeout, TimeUnit.MILLISECONDS); 
					t.getNode().setConnected(true); //dolacz ponownie wezel
					monitoringResult.add(t.result);
					Logger.logEvent(t.getNode().getNodeName() + ": zebrano dane", Logger.LOG_INFO);
				} catch (ExecutionException e) {
					Logger.logEvent("Blad wykonania watku monitora wezla" 
									+ t.getNode().getNodeName(), Logger.LOG_STATUS);
				} catch (TimeoutException e) {
					Logger.logEvent("Utracono polaczenie z wezlem: "+ t.getNode().getNodeName(), Logger.LOG_STATUS);					
					t.getNode().setConnected(false); 
				} catch (InterruptedException e) {
					Logger.logEvent("Przerwano watek monitora wezla" + t.getNode().getNodeName(), Logger.LOG_STATUS);
				} 					
			}				

			for(MonitorListener l : listeners)
				l.monitoringDone(monitoringResult);	
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				for(MonitorListener l : listeners)
					l.monitoringInterrupted();
				Logger.logEvent("Watek monitora wezlow przerwany", Logger.LOG_INFO);
				return;
			}
			
			startedTasks.clear();
		}	
		
		Logger.logEvent("Monitorowanie wezlow zakonczone", Logger.LOG_INFO);
	}
		
	public void stop() {
		synchronized(this) {
			this.stopped = true;
		}
	}

	public boolean isStopped() {
		synchronized(this) {
			return stopped;
		}
	}

	public void setNodes(Collection<NodeInfo> nodes) {
		this.nodes = nodes;
	}

	public void setTimeout(int timeout) {
		this.msTimeout = timeout;
	}

	public long getTimeout() {
		return msTimeout;
	}

	public void registerListener(MonitorListener listener) {
		this.listeners.add(listener);
	}

	public void unregisterListener(MonitorListener listener) {
		this.listeners.remove(listener);
	}
}

